'''
@作者：林风
@日期：2021/1/18 16:30

'''

# 在Class内部，可以有属性和方法，而外部代码可以通过直接调用实例变量的方法来操作数据，这样，就隐藏了内部的复杂逻辑。

# 但是，一般的定义并不意味着外部代码不能修改数据，比如，Student类有一个name属性和score属性。
#   如果要让外部代码不能修改类属性，可以把属性定义为私有属性，外部代码只能通过方法来访问和修改属性。
# 私有属性的定义方法是，在属性名前面加上两个下划线__，如__name__。
#   这样，外部代码就无法直接访问__name属性，只能通过类实例的方法来访问和修改name属性。

class test:
    def __init__(self, name, age):
        self.__name = name  # 私有属性通常使用单下划线作为前缀，而不是双下划线
        self.age = age

    def get_name(self):
        return self.__name

t = test("Alice", 20)
print(t.get_name())
print(t.age)

# 检查属性是否存在
print(hasattr(t, "age"))  # True
print(getattr(t, "age"))    # 20
print(setattr(t, "age", 30))   # 设置属性值 返回值是True, 表示设置成功。
print(t.age)   # 30
# 一般判断 属性是否存在，再得到属性值，再设置属性值，这样可以避免因属性不存在而导致的异常。
# 也可直接，
print(t.age)  # 但是，如果属性不存在，则会导致AttributeError异常。最好的是先判断 属性是否存在，再得到属性值，或设置属性值。

print(hasattr(t, "name"))  # False  因为name是私有属性，外部代码无法直接访问。，判断为False。
# 也可用 hasattr,getattr setattr ,得到对象的其他属性。如：类名，文件名，模块名，函数名，文档字符串等。


## 把下面的Student对象的gender字段对外隐藏起来，用get_gender()和set_gender()代替，并检查参数有效性：
#  应该还要有has_gender()方法，用来检查gender属性是否存在。
class Student:
    def __init__(self, name, gender):
        self.name = name
        self.__gender = gender

    def has_gender(self, gender):
        return gender == self.__gender  # if self.__gender

    def get_gender(self):
        return self.__gender

    def set_gender(self, gender):
        if gender in ['male', 'female']:
            self.__gender = gender
        else:
            print('性别只能是male或female')

# 测试:
bart = Student('Bart', 'male')
if bart.get_gender() != 'male':    # 使用get_gender()方法获取__gender属性  因为__gender是私有属性，所以外部代码无法直接访问
    print('测试失败!')
else:
    bart.set_gender('female')
    if bart.get_gender() != 'female':
        print('测试失败!')
    else:
        print('测试成功!')



